package 四递归;

/**
 * @Author XuZhuHong
 * @CreateTime 2021/9/14 19:49
 * 八皇后
 */
public class Queue8 {
    /**
     * 1) 第一个皇后先放第一行第一列
     * 2) 第二个皇后放在第二行第一列、然后判断是否 OK， 如果不 OK，继续放在第二列、第三列、依次把所有列都
     * 放完，找到一个合适
     * 3) 继续第三个皇后，还是第一列、第二列……直到第 8 个皇后也能放在一个不冲突的位置，算是找到了一个正确
     * 解
     * 4) 当得到一个正确解时，在栈回退到上一个栈时，就会开始回溯，即将第一个皇后，放到第一列的所有正确解，
     * 全部得到. 5) 然后回头继续第一个皇后放第二列，后面继续循环执行 1,2,3,4 的步骤
     * 6) 示意图:
     */

    int max = 10;//定义一个数 决定有多少个皇后
    int[] array = new int[max];
    static int count = 0;
    static int judgeCount = 0;

    public static void main(String[] args) {
        Queue8 queue8 = new Queue8();
        queue8.check(0);

        System.out.printf("一共有%d 解法\n", count);
        System.out.printf("一共判断冲突的次数%d 次", judgeCount); // 1.5w
    }

    /**
     * @param n 传入从第几行开始  i则表示在这个行的第几列
     */
    private void check(int n) {
        if (n >= max) {
            //表示这个已经在第九次了 说明前面8次已经过了
            print(array);
            return;
        }
        for (int i = 0; i < max; i++) {
            array[n] = i;
            //为什么下面传n进去而不是i  因为 在里面会比较 从0列开始到n之前一列  如果有相同的  则这个位置也不能用
            if (judge(n)) {//判断是否重复 如果不重复就继续调用  重复的话就进入下次循环
                check(n + 1);
            }
        }
    }

    /**
     * @param n 传入一个位置 看皇后是否可以在这个位置
     * @return
     */
    private boolean judge(int n) {
        judgeCount++;
        // 说明
        //1. array[i] == array[n] 表示判断 第 n 个皇后是否和前面的 n-1 个皇后在同一列
        //2. Math.abs(n-i) == Math.abs(array[n] - array[i]) 表示判断第 n 个皇后是否和第 i 皇后是否在同一斜线
        // n = 1 放置第 2 列 1 n = 1 array[1] = 1
        // Math.abs(1-0) == 1 Math.abs(array[n] - array[i]) = Math.abs(1-0) = 1
        //3. 判断是否在同一行, 没有必要，n 每次都在递增
        for (int i = 0; i < n; i++) {
            //第一个是判断如果之前的位置有和n一样的就 列重复了   这个数组第一个元素代表第一行 而值代表第几列
            //第二个表达式确实没看懂
            if (array[i] == array[n] || Math.abs(n - i) == Math.abs(array[n] - array[i])) {
                return false;
            }
        }
        return true;
    }

    //打印数组
    private void print(int[] array) {
        for (int i : array) {
            System.out.print(i + " ");
        }
        System.out.println();
        count++;
    }
}
